package com.javabi.common.concurrent.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A thread-safe, very simple and fast lock factory. Ensuring sufficient capacity is important as lock contention can
 * occur for different keys.
 */
public class ArrayLockFactory<K> implements ILockFactory<K> {

	private final Lock[] locks;

	public ArrayLockFactory(int capacity, boolean fair) {
		if (capacity < 1) {
			throw new IllegalArgumentException("capacity=" + capacity);
		}
		this.locks = new Lock[capacity];

		// Populate the locks
		for (int i = 0; i < locks.length; i++) {
			locks[i] = new ReentrantLock(fair);
		}
	}

	public ArrayLockFactory(int capacity) {
		this(capacity, false);
	}

	protected int getIndex(K key, int length) {
		// Simple index hash, override for a more effective hash
		int hash = key.hashCode();
		return hash % length;
	}

	@Override
	public Lock getLock(K key) {
		if (key == null) {
			throw new NullPointerException("key");
		}
		int index = getIndex(key, locks.length);
		return locks[index];
	}

}
